package com.pingan.common.core.property;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ReflectionUtils;

/*
 * 一个使用了@Properties的bean对象对应就一个PropertiesInjectionMetadata
 */
public class PropertiesInjectionMetadata {
	protected static final transient Log logger = LogFactory
			.getLog(PropertiesInjectionMetadata.class);

	private Set<Field> injectedFields = new LinkedHashSet<Field>();

	public static final String CLASS_SEPARATOR = ":";

	// 可以把用","分隔开的定义转为List
	public static final String ARRAY_SEPARATOR = ",";

	public void addInjectedField(Field element) {
		if (element.isAnnotationPresent(Properties.class))
			this.injectedFields.add(element);
	}

	@SuppressWarnings("unchecked")
	public void injectFields(final java.util.Properties pros, Object bean,
			String beanName) {
		if (injectedFields.isEmpty()) {
			logger.debug("the class has no properties to inject");
			return;
		}

		for (Field field : injectedFields) {
			if (logger.isDebugEnabled())
				logger.debug(" fieldType : " + field.getType()
						+ ",fieldName : " + field.getName());

			Properties p = field.getAnnotation(Properties.class);
			String value = pros.getProperty(p.name());
			if (value != null) {
				try {
					ReflectionUtils.makeAccessible(field);
					Class<?> type = field.getType();
					// 判定此Collection.class与指定的 type 参数所表示的类或接口是否相同，或是否是其超类或超接口。
					if (Collection.class.isAssignableFrom(type)) {
						Collection<Object> collection = (Collection<Object>) type
								.newInstance();
						String[] array = StringUtils.split(value,
								ARRAY_SEPARATOR);
						for (String v : array)
							collection.add(getObject(p.generic(), v));

						field.set(bean, collection);
					} else {
						field.set(bean, getObject(type, value));
					}
				} catch (Exception e) {
					throw new PropertiesInjectException(
							" --- inject properties error when create "
									+ beanName, e);
				}
			}
		}
	}

	private Object getObject(Class<?> type, String value) throws Exception {
		if (type.equals(String.class)) {
			return value;
		} else if (type.equals(int.class) || type.equals(Integer.class)) {
			return Integer.valueOf(value);
		} else if (type.equals(long.class) || type.equals(Long.class)) {
			return Long.valueOf(value);
		} else if (type.equals(boolean.class) || type.equals(Boolean.class)) {
			if (value.equals("true"))
				return true;
			else
				return false;
		} else {
			Object[] properties = StringUtils.split(value, CLASS_SEPARATOR);
			Class<?>[] classes = new Class<?>[properties.length];
			for (int i = 0; i < properties.length; i++)
				classes[i] = String.class;
			Constructor<?> c = type.getConstructor(classes);
			if (c != null) {
				Object o = c.newInstance(properties);
				return o;
			} else {
				throw new NoSuchMethodException(
						"no constructor(String... classes) for "
								+ type.getName() + " , the value is " + value);
			}
		}
	}

	public Set<Field> getInjectedFields() {
		return injectedFields;
	}

}
